#!/usr/bin/env python3
#
# make-pci-ids - Creates a file containing PCI IDs.
# It use the databases from
# https://github.com/pciutils/pciids/raw/master/pci.ids
# to create our file epan/dissectors/pci-ids.c
#
# Wireshark - Network traffic analyzer
#
# By Caleb Chiu <caleb.chiu@macnica.com>
# Copyright 2021
#
# SPDX-License-Identifier: GPL-2.0-or-later
#

import re
import string
import sys
import urllib.request, urllib.error, urllib.parse

OUTPUT_FILE = "epan/pci-ids.c"

code_prefix = """ *
 * Generated by tools/make-pci-ids.py
 * By Caleb Chiu <caleb.chiu@macnica.com>
 * Copyright 2021
 *
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include <config.h>
#include \"pci-ids.h\"

typedef struct
{
  guint16 vid;
  guint16 did;
  guint16 svid;
  guint16 ssid;
  gchar *name;

} pci_id_t;

typedef struct
{
  guint16 vid;
  guint16 count;
  pci_id_t *ids_ptr;

} pci_vid_index_t;

"""

code_postfix = """
static pci_vid_index_t *get_vid_index(guint16 vid)
{
    guint32 start_index = 0;
    guint32 end_index = 0;
    guint32 idx = 0;

    end_index = sizeof(pci_vid_index)/sizeof(pci_vid_index[0]);

    while(start_index != end_index)
    {
        if(end_index - start_index == 1)
        {
            if(pci_vid_index[start_index].vid == vid)
                return &pci_vid_index[start_index];

            break;
        }

        idx = (start_index + end_index)/2;

        if(pci_vid_index[idx].vid < vid)
            start_index = idx;
        else
        if(pci_vid_index[idx].vid > vid)
            end_index = idx;
        else
            return &pci_vid_index[idx];

    }

    return NULL;

}

const char *pci_id_str(guint16 vid, guint16 did, guint16 svid, guint16 ssid)
{
    unsigned int i;
    static char *not_found = \"Not found\";
    pci_vid_index_t *index_ptr;
    pci_id_t *ids_ptr;

    index_ptr = get_vid_index(vid);

    if(index_ptr == NULL)
        return not_found;

    ids_ptr = index_ptr->ids_ptr;
    for(i = 0; i < index_ptr->count; ids_ptr++, i++)
        if(vid == ids_ptr->vid &&
           did == ids_ptr->did &&
           svid == ids_ptr->svid &&
           ssid == ids_ptr->ssid)
           return ids_ptr->name;
    return  not_found;

}"""


id_list=[]
count_list=[]

def main():
    req_headers = { 'User-Agent': 'Wireshark make-pci-ids' }
    req = urllib.request.Request('https://github.com/pciutils/pciids/raw/master/pci.ids', headers=req_headers)
    response = urllib.request.urlopen(req)
    lines = response.read().decode('UTF-8', 'replace').splitlines()

    foutput = open(OUTPUT_FILE, "w", encoding="utf-8")

    print("/* pci-ids.c\n *", file = foutput)
    print(" * pci-ids.c is based on the pci.ids of The PCI ID Repository:", file = foutput)
    vid = -1
    did = -1
    svid = -1
    ssvid = -1
    entries = 0;
    line_num = 0;

    for line in lines:
        line = line.strip('\n')
        line_num += 1

        if line_num <= 15:
             line = line.replace('#', ' ', 1)
             line = line.lstrip()
             line = line.replace("GNU General Public License","GPL")
             if line:
                 line = ' * ' + line
             else:
                 line = ' *' + line 
             print(line, file = foutput)
        if line_num == 15:
             foutput.write(code_prefix)

        line = line.replace("\\","\\\\") 
        line = line.replace("\"","\\\"")
        line = line.replace("?","?-") 
        tabs = len(line) - len(line.lstrip('\t'))
        if tabs == 0:
             #print line
             words = line.split(" ", 1)
             if len(words) < 2:
                continue
             if len(words[0]) != 4:
                continue
             if all(c in string.hexdigits for c in words[0]):
                hex_int = int(words[0], 16)
                if vid != -1:
                    print("};/* pci_vid_%04X[] */"% (vid), file = foutput)
                    print("\n", file = foutput)
                    count_list.append(entries)
                vid = hex_int;
                entries = 1;
                did = -1
                svid = -1
                ssid = -1
                print("pci_id_t pci_vid_%04X[] = {"% (vid), file = foutput)
                print("{0x%04X, 0xFFFF, 0xFFFF, 0xFFFF, \"%s(0x%04X)\"},"% (vid, words[1], vid), file = foutput)
                id_list.append(vid);
                continue;

        if tabs == 1:
             line = line.strip('\t')
             words = line.split(" ", 1)
             if len(words) < 2:
                continue
             if len(words[0]) != 4:
                continue
             if all(c in string.hexdigits for c in words[0]):
                hex_int = int(words[0], 16)
                did = hex_int
                svid = -1
                ssid = -1
                print("{0x%04X, 0x%04X, 0xFFFF, 0xFFFF, \"%s(0x%04X)\"},"% (vid, did, words[1], did), file = foutput)
                entries += 1;
                continue;

        if tabs == 2:
             line = line.strip('\t')
             words = line.split(" ", 2)
             if len(words[0]) != 4:
                continue
             if all(c in string.hexdigits for c in words[0]):
                hex_int = int(words[0], 16)
                svid = hex_int

             if all(c in string.hexdigits for c in words[1]):
                hex_int = int(words[1], 16)
                ssid = hex_int
             print("{0x%04X, 0x%04X, 0x%04X, 0x%04X, \"%s(0x%04X-0x%04X)\"},"% (vid, did, svid, ssid, words[2], svid, ssid), file = foutput)
             entries += 1;
             svid = -1
             ssid = -1
             continue;

    print("};/* pci_vid_%04X[] */"% (vid), file = foutput)
    count_list.append(entries)

    print("\npci_vid_index_t pci_vid_index[] = {", file = foutput)

    length = len(id_list)
    for i in range(length):
        print("{0x%04X, %d, pci_vid_%04X },"% (id_list[i], count_list[i],id_list[i]), file = foutput)

    print("};/* We have %d VIDs */"% (length), file = foutput)

    foutput.write(code_postfix)
    foutput.close()

if __name__ == '__main__':
    main()
